﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace PhysicsSimulator
{
    class CTurnable : CGameObject
    {
        private float _angle = 0.0f;
        public float Angle
        {
            get
            {
                return _angle;
            }
            set
            {
                _angle = value;
            }
        }

        private float _angleVelocity = 0.0f;
        public float AngleVelocity
        {
            get
            {
                return _angleVelocity;
            }
            set
            {
                _angleVelocity = value;
            }
        }

        private Vector2 _position;
        public Vector2 Position
        {
            get
            {
                return _position;
            }
            set
            {
                _position = value;
            }
        }

        float _radial = 0.0f;
        float _weight = 0.0f;
        float I = 0.0f;
        float _power = 0.0f;

        public float Power
        {
            get
            {
                return _power;
            }
        }

        public int Direction
        {
            get
            {
                return (int)(_angleVelocity / Math.Abs(_angleVelocity));
            }
        }

        CSprite _centerSprite = null;
        CSprite _turnableSprite = null;

        List<CTurnableObject> _turnableObjects = new List<CTurnableObject>();



        public CTurnable(SpriteBatch spriteBatch)
            : base(spriteBatch)
        {
            _weight = Settings.TurnableWeight;
            _radial = Settings.TurnableRadial;
            I = 0.5f * (_weight * _radial * _radial);
        }

        public override void Init(ContentManager contentManager)
        {
            _centerSprite = new CSprite(contentManager.Load<Texture2D>("Images/Turnable/turnable-center"));
            _turnableSprite = new CSprite(contentManager.Load<Texture2D>("Images/Turnable/turnable-body"));

            base.Init(contentManager);
        }

        public override void Update(GameTimerEventArgs timer)
        {
            _power = 0.5f * I * _angleVelocity * _angleVelocity;
            float dangle = (float)timer.ElapsedTime.TotalSeconds * _angleVelocity;
            if (dangle > 0)
            {
                _angle += dangle;

                foreach (CTurnableObject obj in _turnableObjects)
                {
                    Vector2 newPo = VectorHelper.RotatePoint(dangle, obj.Position, _position);
                    obj.Position = newPo;
                    obj.UpdateForceVector(_angleVelocity, _position);
                }
            }

            base.Update(timer);
        }

        public override void Draw(GameTimerEventArgs timer)
        {
            SpriteBatch.Draw(_turnableSprite.Texture,
                             _position,
                             null,
                             Color.White,
                             _angle,
                             _turnableSprite.Origin,
                             _turnableSprite.Scale,
                             SpriteEffects.None,
                             0);

            SpriteBatch.Draw(_centerSprite.Texture,
                             _position,
                             null,
                             Color.White,
                             0.0f,
                             _centerSprite.Origin,
                             _centerSprite.Scale,
                             SpriteEffects.None,
                             0);
            base.Draw(timer);
        }

        public bool IsPointInside(Vector2 point)
        {
            float l = Vector2.Subtract(point, _position).Length();
            if (l < _turnableSprite.Width / 2)
            {
                return true;
            }
            return false;
        }

        public void UpdateDragState(Vector2 lastPoint, Vector2 currPoint)
        {
            Vector2 PA = Vector2.Subtract(lastPoint, _position);
            Vector2 PB = Vector2.Subtract(currPoint, _position);

            double cos_angle = (PA.X * PB.X + PA.Y * PB.Y) / (PA.Length() * PB.Length());
            double angle = Math.Acos(cos_angle);
            if (angle > 0)
            {
                _angle += (float)angle;
                foreach (CTurnableObject obj in _turnableObjects)
                {
                    Vector2 newPo = VectorHelper.RotatePoint((float)angle, obj.Position, _position);
                    obj.Position = newPo;
                    obj.UpdateForceVector(_angleVelocity, _position);
                }
            }
        }

        public void ReleaseDrag(Vector2 lastPoint, Vector2 currPoint)
        {
            _angleVelocity = Vector2.Subtract(currPoint, lastPoint).Length() / 7.5f;
        }

        public void CheckPlusObject(CTurnableObject newobject)
        {
            Vector2 l = Vector2.Subtract(_position, newobject.Position);

            if (l.Length() < _turnableSprite.Width / 2)
            {
                bool accept_add = true;

                foreach (CTurnableObject obj in _turnableObjects)
                {
                    if (obj.getBoundRect().Intersects(newobject.getBoundRect()))
                    {
                        accept_add = false;
                        break;
                    }
                }
                if (accept_add)
                    AddObject(newobject);
                else
                {
                    System.Windows.MessageBox.Show("Overlaped with other object!", "FAIL", System.Windows.MessageBoxButton.OK);
                    newobject.SetIdleState();
                }
            }
            else
            {
                RemoveObject(newobject);
                newobject.SetIdleState();
            }
        }

        public void AddObject(CTurnableObject tobject)
        {
            _turnableObjects.Add(tobject);
            tobject.SetRollingState();

            Vector2 l = Vector2.Subtract(_position, tobject.Position);
            float ratio = l.Length() / (_turnableSprite.Width / 2);
            float r = ratio * _radial;

            float I1 = I;
            float I2 = I + r * r * tobject.Weight;

            _angleVelocity = (I1 / I2) * _angleVelocity;
            I = I2;
        }

        public void RemoveObject(CTurnableObject tobject)
        {
            if (_turnableObjects.Contains(tobject))
            {
                _turnableObjects.Remove(tobject);

                float I1 = I;
                float I2 = GetCurrentI();

                _angleVelocity = (I1 / I2) * _angleVelocity;

                I = I2;
            }
            else
            {

            }
        }

        public bool IsPlaying()
        {
            if (_angleVelocity == 0)
                return false;
            return true;
        }

        public void Reset()
        {
            _angleVelocity = 0;
            I = 0.5f * _weight * _radial;//I default value

            foreach (CTurnableObject to in _turnableObjects)
            {                
                to.SetIdleState();
            }
            _turnableObjects.Clear();
        }

        float GetCurrentI()
        {
            float I = 0.5f * _weight * _radial;
            foreach (CTurnableObject obj in _turnableObjects)
            {
                Vector2 l = Vector2.Subtract(_position, obj.Position);
                if (l.Length() < _turnableSprite.Width / 2)
                {
                    float r = (l.Length() / _turnableSprite.Width / 2) * _radial;
                    I += r * r * obj.Weight;
                }
            }
            return I;
        }
    }
}
